package cn.wlinker.driver.bacnet.utils;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.log.StaticLog;
import cn.wlinker.driver.bacnet.domain.BacnetLocalDeviceBean;
import com.serotonin.bacnet4j.LocalDevice;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * LocalDevice缓存工具类
 *
 * @author gxsjx
 * @version 1.0
 * @date 2022/9/30
 * Copyright © wlinker.cn
 */
public class LocalDeviceCacheUtils {

    private static final Map<String, LocalDevice> LOCAL_DEVICE_MAP = new ConcurrentHashMap<>();

    private static String getKey(String broadcastAddress, Integer networkPrefixLength, String localBindAddress) {
        if (CharSequenceUtil.isBlank(broadcastAddress)) {
            broadcastAddress = "?";
        }
        if (ObjectUtil.isEmpty(networkPrefixLength)) {
            networkPrefixLength = 0;
        }
        if (CharSequenceUtil.isBlank(localBindAddress)) {
            localBindAddress = "?";
        }
        return CharSequenceUtil.format("{}_{}_{}", broadcastAddress, networkPrefixLength, localBindAddress);
    }

    private static String getKey(BacnetLocalDeviceBean bacnetLocalDeviceBean) {
        String broadcastAddress = bacnetLocalDeviceBean.getBroadcastAddress();
        Integer networkPrefixLength = bacnetLocalDeviceBean.getNetworkPrefixLength();
        String localBindAddress = bacnetLocalDeviceBean.getLocalBindAddress();
        return getKey(broadcastAddress, networkPrefixLength, localBindAddress);
    }

    private static LocalDevice getLocalDeviceInCache(BacnetLocalDeviceBean bacnetLocalDeviceBean) {
        String key = getKey(bacnetLocalDeviceBean);
        String localBindAddress = bacnetLocalDeviceBean.getLocalBindAddress();
        LOCAL_DEVICE_MAP.keySet().forEach(t -> {
            if (!key.equalsIgnoreCase(t) && t.contains(localBindAddress)) {
                LocalDevice localDevice = LOCAL_DEVICE_MAP.get(t);
                if (ObjectUtil.isNotNull(localDevice)) {
                    try {
                        localDevice.terminate();
                    } catch (Exception exception) {
                        StaticLog.warn(exception.getMessage());
                    }
                }
            }
        });
        return LOCAL_DEVICE_MAP.get(key);
    }

    public static LocalDevice get(BacnetLocalDeviceBean bacnetLocalDeviceBean) {
        return getLocalDeviceInCache(bacnetLocalDeviceBean);
    }

    public static Boolean put(BacnetLocalDeviceBean bacnetLocalDeviceBean, LocalDevice localDevice) {
        String key = getKey(bacnetLocalDeviceBean);
        if (localDevice.isInitialized()) {
            LOCAL_DEVICE_MAP.put(key, localDevice);
            return true;
        }
        return false;
    }
}
